package actor

import (
	"context"
	"sync"
	"time"

	proto "xagent/proto/v1"
)

// ActorThought represents a single thought in the thought chain
type ActorThought struct {
	Content    string
	Reasoning  string
	Plan       []string
	Critical   string
	NextAction string
	Timestamp  time.Time
}

// ActorThoughtChain represents a chain of thoughts
type ActorThoughtChain struct {
	Thoughts []ActorThought
	mutex    sync.RWMutex
}

// AddThought adds a new thought to the chain
func (tc *ActorThoughtChain) AddThought(thought *ActorThought) {
	tc.mutex.Lock()
	defer tc.mutex.Unlock()
	tc.Thoughts = append(tc.Thoughts, *thought)
}

// ActorAction represents an executable action
type ActorAction interface {
	Name() string
	Run(ctx context.Context, input string) (*proto.AgentMessage, error)
}

// ActorMessage represents a message in the message pool
type ActorMessage struct {
	ID        string
	Type      string
	Content   string
	Metadata  map[string]interface{}
	Timestamp time.Time
}

// ActorMessagePool manages message routing and observers
type ActorMessagePool struct {
	messages  []*proto.AgentMessage
	observers map[string]chan *proto.AgentMessage
	mutex     sync.RWMutex
}

// NewActorMessagePool creates a new message pool
func NewActorMessagePool() *ActorMessagePool {
	return &ActorMessagePool{
		messages:  make([]*proto.AgentMessage, 0),
		observers: make(map[string]chan *proto.AgentMessage),
	}
}

// AddMessage adds a message to the pool
func (mp *ActorMessagePool) AddMessage(msg *proto.AgentMessage) {
	mp.mutex.Lock()
	defer mp.mutex.Unlock()

	mp.messages = append(mp.messages, msg)
	for _, ch := range mp.observers {
		select {
		case ch <- msg:
		default:
			// Skip if channel is full
		}
	}
}

// AddObserver adds an observer to the pool
func (mp *ActorMessagePool) AddObserver(id string) chan *proto.AgentMessage {
	mp.mutex.Lock()
	defer mp.mutex.Unlock()

	ch := make(chan *proto.AgentMessage, 100)
	mp.observers[id] = ch
	return ch
}

// RemoveObserver removes an observer from the pool
func (mp *ActorMessagePool) RemoveObserver(id string) {
	mp.mutex.Lock()
	defer mp.mutex.Unlock()

	if ch, ok := mp.observers[id]; ok {
		close(ch)
		delete(mp.observers, id)
	}
}

// GetMessages returns all messages in the pool
func (mp *ActorMessagePool) GetMessages() []*proto.AgentMessage {
	mp.mutex.RLock()
	defer mp.mutex.RUnlock()

	messages := make([]*proto.AgentMessage, len(mp.messages))
	copy(messages, mp.messages)
	return messages
}
